package com.mask.im.business.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mask.im.business.model.entity.SysResourceEntity;
import com.mask.im.business.model.entity.ResourceRole;
import com.mask.im.business.common.exception.BusinessException;
import com.mask.im.business.mapper.SysResourceMapper;
import com.mask.im.business.mapper.ResourceRoleMapper;
import com.mask.im.business.model.dto.LabelOptionDTO;
import com.mask.im.business.model.dto.ResourceDTO;
import com.mask.im.business.model.vo.ConditionVO;
import com.mask.im.business.model.vo.ResourceVO;
import com.mask.im.business.service.SysResourceService;
import com.mask.im.business.common.util.BeanCopy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.mask.im.business.common.constant.CommonConstant.FALSE;


/**
 * 资源管理
 *
 * @author jian
 */
@Service
public class SysResourceServiceImpl extends ServiceImpl<SysResourceMapper, SysResourceEntity> implements SysResourceService {
    //    @Autowired
    private RestTemplate restTemplate;

    //    @Autowired
    private ResourceRoleMapper roleResourceMapper;


//    @Autowired

    @SuppressWarnings("all")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void importSwagger() {
        this.remove(null);
        roleResourceMapper.delete(null);
        List<SysResourceEntity> sysResourceEntities = new ArrayList<>();
        Map<String, Object> data = restTemplate.getForObject("http://localhost:8080/v2/api-docs", Map.class);
        List<Map<String, String>> tagList = (List<Map<String, String>>) data.get("tags");
        tagList.forEach(item -> {
            SysResourceEntity sysResourceEntity = SysResourceEntity.builder()
                    .resourceName(item.get("name"))
                    .isAnonymous(FALSE)
                    .createTime(LocalDateTime.now())
                    .build();
            sysResourceEntities.add(sysResourceEntity);
        });
        this.saveBatch(sysResourceEntities);
        Map<String, Integer> permissionMap = sysResourceEntities.stream()
                .collect(Collectors.toMap(SysResourceEntity::getResourceName, SysResourceEntity::getId));
        sysResourceEntities.clear();
        Map<String, Map<String, Map<String, Object>>> path = (Map<String, Map<String, Map<String, Object>>>) data.get("paths");
        path.forEach((url, value) -> value.forEach((requestMethod, info) -> {
            String permissionName = info.get("summary").toString();
            List<String> tag = (List<String>) info.get("tags");
            Integer parentId = permissionMap.get(tag.get(0));
            SysResourceEntity sysResourceEntity = SysResourceEntity.builder()
                    .resourceName(permissionName)
                    .url(url.replaceAll("\\{[^}]*\\}", "*"))
                    .parentId(parentId)
                    .requestMethod(requestMethod.toUpperCase())
                    .isAnonymous(FALSE)
                    .createTime(LocalDateTime.now())
                    .build();
            sysResourceEntities.add(sysResourceEntity);
        }));
        this.saveBatch(sysResourceEntities);
    }

    @Override
    public void saveOrUpdateResource(ResourceVO resourceVO) {
        SysResourceEntity sysResourceEntity = BeanCopy.singleCopy(resourceVO, SysResourceEntity.class);
        this.saveOrUpdate(sysResourceEntity);
//        filterInvocationSecurityMetadataSource.clearDataSource();
    }

    @Override
    public void deleteResource(Integer resourceId) {
        Integer count = roleResourceMapper.selectCount(new LambdaQueryWrapper<ResourceRole>()
                .eq(ResourceRole::getResourceId, resourceId));
        if (count > 0) {
            throw new BusinessException("该资源下存在角色");
        }
        List<Integer> resourceIds = this.baseMapper.selectList(new LambdaQueryWrapper<SysResourceEntity>()
                        .select(SysResourceEntity::getId).
                        eq(SysResourceEntity::getParentId, resourceId))
                .stream()
                .map(SysResourceEntity::getId)
                .collect(Collectors.toList());
        resourceIds.add(resourceId);
        this.baseMapper.deleteBatchIds(resourceIds);
    }

    @Override
    public List<ResourceDTO> listResources(ConditionVO conditionVO) {
        List<SysResourceEntity> sysResourceEntities = this.baseMapper.selectList(new LambdaQueryWrapper<SysResourceEntity>()
                .like(StringUtils.isNotBlank(conditionVO.getKeywords()), SysResourceEntity::getResourceName, conditionVO.getKeywords()));
        List<SysResourceEntity> parents = listResourceModule(sysResourceEntities);
        Map<Integer, List<SysResourceEntity>> childrenMap = listResourceChildren(sysResourceEntities);
        List<ResourceDTO> resourceDTOs = parents.stream().map(item -> {
            ResourceDTO resourceDTO = BeanCopy.singleCopy(item, ResourceDTO.class);
            List<ResourceDTO> child = BeanCopy.listCopy(childrenMap.get(item.getId()), ResourceDTO.class);
            resourceDTO.setChildren(child);
            childrenMap.remove(item.getId());
            return resourceDTO;
        }).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(childrenMap)) {
            List<SysResourceEntity> childrenList = new ArrayList<>();
            childrenMap.values().forEach(childrenList::addAll);
            List<ResourceDTO> childrenDTOs = childrenList.stream()
                    .map(item -> BeanCopy.singleCopy(item, ResourceDTO.class))
                    .collect(Collectors.toList());
            resourceDTOs.addAll(childrenDTOs);
        }
        return resourceDTOs;
    }

    @Override
    public List<LabelOptionDTO> listResourceOption() {
        List<SysResourceEntity> sysResourceEntities = this.baseMapper.selectList(new LambdaQueryWrapper<SysResourceEntity>()
                .select(SysResourceEntity::getId, SysResourceEntity::getResourceName, SysResourceEntity::getParentId)
                .eq(SysResourceEntity::getIsAnonymous, FALSE));
        List<SysResourceEntity> parents = listResourceModule(sysResourceEntities);
        Map<Integer, List<SysResourceEntity>> childrenMap = listResourceChildren(sysResourceEntities);
        return parents.stream().map(item -> {
            List<LabelOptionDTO> list = new ArrayList<>();
            List<SysResourceEntity> children = childrenMap.get(item.getId());
            if (CollectionUtils.isNotEmpty(children)) {
                list = children.stream()
                        .map(sysResourceEntity -> LabelOptionDTO.builder()
                                .id(sysResourceEntity.getId())
                                .label(sysResourceEntity.getResourceName())
                                .build())
                        .collect(Collectors.toList());
            }
            return LabelOptionDTO.builder()
                    .id(item.getId())
                    .label(item.getResourceName())
                    .children(list)
                    .build();
        }).collect(Collectors.toList());
    }


    private List<SysResourceEntity> listResourceModule(List<SysResourceEntity> sysResourceEntityList) {
        return sysResourceEntityList.stream()
                .filter(item -> Objects.isNull(item.getParentId()))
                .collect(Collectors.toList());
    }

    private Map<Integer, List<SysResourceEntity>> listResourceChildren(List<SysResourceEntity> sysResourceEntityList) {
        return sysResourceEntityList.stream()
                .filter(item -> Objects.nonNull(item.getParentId()))
                .collect(Collectors.groupingBy(SysResourceEntity::getParentId));
    }
}

